﻿using System;
using System.Collections;
using System.Collections.Generic;
using CoreEx.Common.Extensions;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;

namespace CoreEx.Common.Implementation.Extensions
{
    /// <summary>
    /// A list of <see cref="PluralRule"/> instances. 
    /// </summary>
    [Implements(typeof(IPluralRules),LifecycleType.Singleton)]
    public class PluralRules : IPluralRules, IInitialize
    {
        private readonly IDictionary<string, string> _pluralDictionary = new Dictionary<string, string>();
        private readonly IDictionary<string, string> _singularDictionary = new Dictionary<string, string>();
        private readonly IList<PluralRule> _nouns = new List<PluralRule>();

        private static readonly object _syncRoot = new object();

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator<PluralRule> GetEnumerator()
        {
            return _nouns.GetEnumerator();
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// <summary>
        /// Adds a new <see cref="PluralRule"/> to the list.
        /// </summary>
        /// <param name="noun">The noun in its plural and singular form.</param>
        /// <exception cref="ArgumentException">Thrown if the plural or singular form of the noun is already in the list.</exception>
        public void Add(PluralRule noun)
        {
            lock (_syncRoot)
            {
                if (_pluralDictionary.ContainsKey(noun.PluralForm) ||
                    _singularDictionary.ContainsKey(noun.SingularForm))
                {
                    throw new ArgumentException("The noun must be unique.");
                }

                _singularDictionary.Add(noun.SingularForm, noun.PluralForm);
                _pluralDictionary.Add(noun.PluralForm, noun.SingularForm);
                _nouns.Add(noun);
            }
        }

        /// <summary>
        /// Returns a list of nouns indexed by its plural form.
        /// </summary>
        /// <returns><see cref="IDictionary{TKey,TValue}"/></returns>
        public IDictionary<string, string> AsPluralDictionary()
        {
            return _pluralDictionary;
        }

        /// <summary>
        /// Returns a list of nouns indexed by its singular form.
        /// </summary>
        /// <returns><see cref="IDictionary{TKey,TValue}"/></returns>
        public IDictionary<string, string> AsSingularDictionary()
        {
            return _singularDictionary;
        }

        /// <summary>
        /// Initializes this service instance.
        /// </summary>
        /// <param name="source">The <see cref="IServiceContainer"/> that created this instance.</param>
        public void Initialize(IServiceContainer source)
        {            
            Add(new PluralRule { SingularForm = "criterion",PluralForm = "criteria" });
            Add(new PluralRule { SingularForm = "woman", PluralForm = "women", });
            Add(new PluralRule { SingularForm = "man", PluralForm = "men" });
            Add(new PluralRule { SingularForm = "analysis", PluralForm = "analysis" });
            Add(new PluralRule { SingularForm = "child", PluralForm = "children" });
            Add(new PluralRule { SingularForm = "diagnosis", PluralForm = "diagnoses" });
            Add(new PluralRule { SingularForm = "medium", PluralForm = "media" });
            Add(new PluralRule { SingularForm = "series", PluralForm = "series" });
            Add(new PluralRule { SingularForm = "leaf", PluralForm = "leaves" });
            Add(new PluralRule { SingularForm = "y", PluralForm = "ies" });
            Add(new PluralRule { SingularForm = "ch", PluralForm = "ches" });
            Add(new PluralRule { SingularForm = "ce", PluralForm = "ces" });
            Add(new PluralRule { SingularForm = "x", PluralForm = "xes" });
            Add(new PluralRule { SingularForm = "s", PluralForm = "ses" });
            Add(new PluralRule { SingularForm = "z", PluralForm = "zzes" });
            Add(new PluralRule { SingularForm = "f", PluralForm = "ves" });
            Add(new PluralRule { SingularForm = "isis", PluralForm = "ises" });
            Add(new PluralRule { SingularForm = "asis", PluralForm = "ases" });
            Add(new PluralRule { SingularForm = "esis", PluralForm = "eses" });
            Add(new PluralRule { SingularForm = "ive", PluralForm = "ives" });
            Add(new PluralRule { SingularForm = "ey", PluralForm = "eys" });
            Add(new PluralRule { SingularForm = "", PluralForm = "s" });            
        }
    }
}
